#include "Objects.h"

#ifdef _WIN32 
#include <windows.h> 
#endif

namespace Objects
{

Objects::Objects(ModelPool *_mPool, PathFinder *_pathfinder,
		Octree::Box *_Octree, Terrain::Terrain *_ter)
{
	mPool = _mPool;
	pathfinder = _pathfinder;
	Octree = _Octree;
	ter = _ter;
}

Objects::~Objects(void)
{

}

void Objects::control(float t)
{
	for (unsigned int i = 0; i < entity.size(); i++)
	{
		entity[i]->control(t);
	}
}

void Objects::drawEntities(int shaderType)
{
	//glEnable(GL_CULL_FACE);

	if (Octree != NULL)
		Octree->drawEntity(shaderType);

	// draw moving entities
	for (unsigned int i = 0; i < mentity.size(); i++)
	{
		mentity[i]->draw(shaderType);
	}
}

void Objects::drawEntBBox()
{
	for (unsigned int i = 0; i < entity.size(); i++)
	{
		if (entity[i]->getType() != OBJ_GRASS)
			entity[i]->drawBBox();
	}
}

Tree* Objects::insertTree(glm::vec3 _Pos, // entity position
		float _r, // angle
		std::string _Name, // name of entity
		std::string _modelFName, // name of model in pool
		float age) // inserting entity to map
{
	Tree *tBuf = new Tree(_Pos, _r, _Name, _modelFName, mPool, pathfinder);
	tBuf->setAge(age);

	// try to reserve position
	// if position is free (reserve it) and insert new building to octree
	if ((pathfinder->ReservePosition((int) _Pos.x, (int) _Pos.z, tBuf) == FREE)
			&& (Octree != NULL))
	{
		Octree->insertEntity(tBuf);
		entity.push_back(tBuf);
	}
	else
		return NULL;

	return tBuf;
}

Entity* Objects::insertBuilding(glm::vec3 _Pos, // entity position
		float _r, // angle
		std::string _Name, // name of entity
		std::string _modelFName, // name of model in pool
		float age, int type, int status) // inserting entity to map
{
	Entity *tBuf;

	if (type == OBJ_BUILDING)
		tBuf = new Building(_Pos, _r, _Name, _modelFName, mPool, pathfinder);
	else if (type == OBJ_BLUMBERJACK)
		tBuf = new BLumberjack(_Pos, _r, _Name, _modelFName, mPool, pathfinder);
	else if (type == OBJ_BHUNTER)
		tBuf = new BHunter(_Pos, _r, _Name, _modelFName, mPool, pathfinder);
	else if (type == OBJ_BBUILDER)
		tBuf = new BBuilder(_Pos, _r, _Name, _modelFName, mPool, pathfinder);
	else if (type == OBJ_BBANK)
		tBuf = new BBank(_Pos, _r, _Name, _modelFName, mPool, pathfinder);
	else
		return NULL;

	tBuf->setAge(age); // setup age of new building
	tBuf->setStatus(status); // setup status of new building

	// update octree
	if ((pathfinder->CheckBuildingPosition(tBuf->getBBox(), tBuf->get2dPosition())
			&& (Octree != NULL)))
	{
		// create building place
		ter->createBuildPlace(tBuf->getBBox(), tBuf->get2dPosition());

		Octree->insertEntity(tBuf);

		// reserve position
		pathfinder->ReserveBuildingPosition(tBuf->getBBox(), tBuf->get2dPosition(),
				tBuf);

		// insert entity to octree
		Octree->insertEntity(tBuf);
		entity.push_back(tBuf);

		// scale bounding box * offset
		DataTypes::Cube box(tBuf->getBBox()->getVertexes());
		box.Scale(BOUNDING_BOX_OFFSET);

		Octree->updateLocal(box, tBuf->getPos());
	}
	else
	{
		gCon::con->print("Cannot create villager type: %i", type);
		return NULL;
	}

	return tBuf;
}

Deer* Objects::insertDeer(glm::vec3 _Pos, // entity position
		float _r, // angle
		std::string _Name, // name of entity
		std::string _modelFName // name of model in pool
		) // inserting entity to map
{
	Deer *tBuf = new Deer(_Pos, _r, 0.022, _Name, _modelFName, mPool, pathfinder,
			ter);

	if (pathfinder->ReservePosition((int) _Pos.x, (int) _Pos.z, tBuf) == FREE)
	{
		// save id of villager
		mentity.push_back(tBuf);

		// save villager data
		entity.push_back(tBuf);
	}
	else
		return NULL;

	return tBuf;
}

Villager* Objects::insertVillager(glm::vec2 _Pos, // entity position
		float _r, // angle
		std::string _Name, // name of entity
		std::string _modelFName, // name of model in pool
		int type, int status) // inserting entity to map
{
	Villager *tBuf;

	glm::vec2 bufPos = _Pos;

	if (pathfinder->ReservePosition((int) bufPos.x, (int) bufPos.y, tBuf) != FREE)
	{
		// not reserved
		bufPos = pathfinder->getNearestFreePoint(_Pos);
		pathfinder->ReservePosition((int) bufPos.x, (int) bufPos.y, tBuf);
	}

	if (type == OBJ_VILLAGER)
		tBuf = new Villager(
				glm::vec3(bufPos.x, ter->getInterYVal(glm::vec2(bufPos.x, bufPos.y)),
						bufPos.y), _r, 0.05f, _Name, _modelFName, mPool, pathfinder, ter);
	else if (type == OBJ_GATHERER)
		tBuf = new Gatherer(
				glm::vec3(bufPos.x, ter->getInterYVal(glm::vec2(bufPos.x, bufPos.y)),
						bufPos.y), _r, 0.05f, _Name, _modelFName, mPool, pathfinder, ter);
	else if (type == OBJ_BUILDER)
		tBuf = new Builder(
				glm::vec3(bufPos.x, ter->getInterYVal(glm::vec2(bufPos.x, bufPos.y)),
						bufPos.y), _r, 0.05f, _Name, _modelFName, mPool, pathfinder, ter);
	else if (type == OBJ_HUNTER)
		tBuf = new Hunter(
				glm::vec3(bufPos.x, ter->getInterYVal(glm::vec2(bufPos.x, bufPos.y)),
						bufPos.y), _r, 0.05f, _Name, _modelFName, mPool, pathfinder, ter);
	else if (type == OBJ_TAXMAN)
		tBuf = new Taxman(
				glm::vec3(bufPos.x, ter->getInterYVal(glm::vec2(bufPos.x, bufPos.y)),
						bufPos.y), _r, 0.05f, _Name, _modelFName, mPool, pathfinder, ter);
	else
	{
		gCon::con->print("Cannot create villager type: %i", type);
		return NULL;
	}

	// save id of villager
	mentity.push_back(tBuf);

	// save villager data
	entity.push_back(tBuf);

	tBuf->setStatus(status);

	return tBuf;
}

Grass* Objects::insertGrass(glm::vec3 _Pos, // entity position
		float _r, // angle
		std::string _Name, // name of entity
		std::string _modelFName)
{
	Grass *tBuf = new Grass(_Pos, _r, _Name, _modelFName, mPool, pathfinder);

	if ((pathfinder->ReservePosition((int) _Pos.x, (int) _Pos.z, tBuf) == FREE)
			&& (Octree != NULL))
		Octree->insertEntity(tBuf);
	else
		return NULL;

	return tBuf;
}

void Objects::deleteAllEnt()
{
	for (int i = 0; i < (int) entity.size(); i++)
		free(entity[i]);

	entity.clear();
	mentity.clear();
}

unsigned int Objects::getMovingCount()
{
	return mentity.size();
}

unsigned int Objects::getEntityCount()
{
	return entity.size();
}

std::vector<Entity*> Objects::getEntity()
{
	return entity;
}

std::vector<Entity*> Objects::getMentity()
{
	return mentity;
}

void Objects::setOctree(Octree::Box *b)
{
	Octree = b;
}
}